#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "cJSON.h"
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <openssl/md5.h>

#define PORT 8888     // 服务器端口
#define BUF_SIZE 1024 // 缓冲区大小

char *fileMD5 = NULL;

/**
 * @brief 打开配置文件
 *
 */
char *openConfigFile(char const *jsonPath)
{
    // 1. 读取JSON文件（参考之前的文件读取逻辑）
    FILE *fp = fopen(jsonPath, "r");
    if (!fp)
    {
        printf("open file failed\n");
        return NULL;
    }

    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    rewind(fp);
    char *buf = (char *)malloc(file_size + 1);
    fread(buf, 1, file_size, fp);
    buf[file_size] = '\0';
    fclose(fp);

    return buf;
}

char *getFileMD5(char *fileName)
{
    char *md5 = NULL;
    char cmd[128];
    sprintf(cmd, "md5sum %s", fileName);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        perror("popen failed");
        exit(1);
    }
    fscanf(fp, "%s", md5);
    pclose(fp);

    return md5;
}

/**
 * @brief tcp升级线程
 *
 * @param arg
 * @return void*
 */
void *tcpUpgradeThread(void *arg)
{

    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    int socket_tcp = socket(AF_INET, SOCK_STREAM, 0);
    
    int opt = 1;
    // 端口复用
    setsockopt(socket_tcp, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));

    if (socket_tcp == -1)
    {
        perror("socket create failed");
        exit(1);
    }
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8899);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(socket_tcp, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("bind failed");
        exit(1);
    }
    printf("tcp Server bind.\n");

    if (listen(socket_tcp, 5) == -1)
    {
        perror("listen failed");
        exit(1);
    }
    printf("tcp Server listening....\n");

    int client_tcp = accept(socket_tcp, (struct sockaddr *)&client_addr, &client_addr_len);
    if (client_tcp == -1)
    {
        perror("accept failed");
        exit(1);
    }
    printf("tcp Server accept client %s.\n", inet_ntoa(client_addr.sin_addr));

    char buf[BUF_SIZE];
    memset(buf, 0, sizeof(buf));
    // 接收二进制文件
    int fd = 0;

    while (1)
    {
        /* code */

        ssize_t recv_len = recv(client_tcp, buf, BUF_SIZE - 1, 0); // 预留1字节给\0
       
    
        if (strstr(buf, "FILE_SEND_FINISHED"))
        {
            sendto(client_tcp, "RECEVICE_FILE_SUCCESS", sizeof("RECEVICE_FILE_SUCCESS"), 0, (struct sockaddr *)&client_addr, client_addr_len);
        }

        if (recv_len == 0)
        {
            printf("recv finish\n");
            system("sudo unzip update.zip");
            close(fd);
            break;
        }

        // 如果没有则新建，有则打开
        fd = open("update.zip", O_WRONLY | O_CREAT | O_APPEND, 0644);

        if (fd == -1)
        {
            perror("创建文件失败");
            close(client_tcp);
            continue;
        }
        write(fd, buf, recv_len);
    }

    //
}

int main()
{
    // 1. 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket create failed");
        exit(1);
    }

    int opt = 1;
    // 端口复用
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));

    // 2. 初始化服务器地址结构
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;                // IPv4
    server_addr.sin_port = htons(PORT);              // 端口（网络字节序）
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定所有本地IP

    // 3. 绑定地址和端口
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("bind failed");
        close(sockfd);
        exit(1);
    }
    printf("UDP server started on port %d...\n", PORT);

    // 4. 循环接收客户端数据并回复
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    char buf[BUF_SIZE];

    while (1)
    {
        // 接收客户端数据
        ssize_t recv_len = recvfrom(sockfd, buf, BUF_SIZE - 1, 0,
                                    (struct sockaddr *)&client_addr, &client_addr_len);

        if (recv_len == -1)
        {
            perror("recvfrom    ");
            continue;
        }
        buf[recv_len] = '\0'; // 手动添加字符串结束符
                              // 打印客户端信息和数据
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
        printf("Received from %s:%d: %s\n", client_ip, ntohs(client_addr.sin_port), buf);

        if (strstr(buf, "devices/search"))
        {


        //获取自己的ip地址

        

            cJSON *obj = cJSON_CreateObject();
            cJSON_AddStringToObject(obj, "mqttIP", "192.168.0.160");
            cJSON_AddNumberToObject(obj, "mqttPort", 1883);
            cJSON_AddStringToObject(obj, "commandControlTopic", "DataSubmitProcess/CommandControl");
            cJSON_AddStringToObject(obj, "devicesStataTopic", "DataSubmitProcess/DevicesStata");
            char *json_str = cJSON_PrintUnformatted(obj);

            // 回复客户端（示例：原样返回数据）
            sendto(sockfd, json_str, strlen(json_str), 0,
                   (struct sockaddr *)&client_addr, client_addr_len);
        }
        else if (strstr(buf, "devices/update"))
        {
            char *json_str = openConfigFile("/home/hq/ShoppingProjec/data-submit-precess/config.json");

            cJSON *root = cJSON_Parse(json_str);

            if (root == NULL)
            {
                printf("cJSON_Parse failed\n");
                continue;
            }

            cJSON *version = cJSON_GetObjectItem(root, "version");
            double currentVersionNum = atof(version->valuestring);

            cJSON_Delete(root);
            free(json_str);

            printf("recv message: \n %s\n", buf);

            cJSON *originRoot = cJSON_Parse(buf);

            if (originRoot == NULL)
            {
                printf("originRoot cJSON_Parse failed\n");
                continue;
            }

            double originVersion = atof(cJSON_GetObjectItem(originRoot, "version")->valuestring);

            fileMD5 = cJSON_GetObjectItem(originRoot, "fileMD5")->valuestring;
            printf("%s\n", fileMD5);
            cJSON_Delete(originRoot);

            cJSON *replyObj = cJSON_CreateObject();

            printf("originVersion: %f, currentVersionNum: %f\n", originVersion, currentVersionNum);
            if (originVersion > currentVersionNum)
            {
                // 回复客户端（示例：原样返回数据）

                cJSON_AddTrueToObject(replyObj, "isUpdate");

                // 开启tcp升级线程
                pthread_t tcpThread;

                int ret = pthread_create(&tcpThread, NULL, (void *)tcpUpgradeThread, NULL);
                if (ret != 0)
                {
                    printf("pthread_create failed\n");
                }
            }
            else
            {
                cJSON_AddFalseToObject(replyObj, "isUpdate");
            }

            char *replyStr = cJSON_PrintUnformatted(replyObj);
            sendto(sockfd, replyStr, strlen(replyStr), 0,
                   (struct sockaddr *)&client_addr, client_addr_len);

            cJSON_Delete(replyObj);
            free(replyStr);
        }
    }

    close(sockfd);
    return 0;
}
